#include "Utils.h"
#include <stdlib.h>
#include <iostream>
#include "CRC32.h"
#include <sys/stat.h>
#include "../decompressor/zipFileDecompressor.h"

extern LoggerManager* g_logger;

namespace zipUtils
{
    struct stat st_info;

    long calculateSize(FILE* file)
    {
        fseek(file, 0, SEEK_END);
        long size = ftell(file);
        fseek(file, 0, SEEK_SET);
        
        return size;
    }

    void getBytes(FILE* file, char* buffer, size_t size)
    {
        fread(buffer, sizeof (char), size, file);
        fseek(file, 0, SEEK_SET);
    }

    long getCRC32(FILE* file)
    {
        long size = calculateSize(file);
        char *buffer = (char*) malloc(size * sizeof (char));
        getBytes(file, buffer, size);
        long crc = calculateCRC32(buffer, size);
        free(buffer);
        return crc;
    }

    bool isFile(char *path)
    {

        if (path)
        {
            if (stat(path, &st_info) < 0)
            {
                return false;
            }
        }
        return S_ISREG(st_info.st_mode);
    }

    bool isDirectory(const char *path)
    {
        if (path)
        {
            if (stat(path, &st_info) < 0)
            {
                return false;
            }
        }
        return S_ISDIR(st_info.st_mode);
    }

    void copy(char*& buffer, const void* toCopy, size_t since, const size_t size)
    {
        char aux[size];
        memcpy(aux, toCopy, sizeof (toCopy));
        for (int i = 0; i < size; i++)
        {
            buffer[since] = aux[i];
            since++;
        }
    }

    void conCat(char*& buffer, const char* toCopy, size_t since, const size_t size)
    {
        for (int i = 0; i < size; i++)
        {
            buffer[since] = toCopy[i];
            since++;
        }
    }

    tm* getLastModificationTimeAndDate(char* path)
    {
        struct tm* tmModifiedTime;
        struct stat attrib;
        stat(path, &attrib);
        tmModifiedTime = gmtime(&(attrib.st_mtime));
        return tmModifiedTime;
    }

    short parseDateToShort(tm* date)
    {
        char buffer[11];
        strftime(buffer, 11, "%Y:%m:%d", date);
        int year;
        int month;
        int day;
        sscanf(buffer, "%d:%d:%d", &year, &month, &day);
        year -= 1980;
        return (short) (year << 9) | (month << 5) | day; // Store the year month and day in two bytes
    }

    short parseTimeToShort(tm* date)
    {
        char buffer[11];
        strftime(buffer, 11, "%H:%M:%S", date);
        int hour;
        int minute;
        int second;
        sscanf(buffer, "%d:%d:%d", &hour, &minute, &second);
        second /= 2;
        return (short) (hour << 11) | (minute << 5) | second; // Store the hour minute and second in two bytes
    }

    bool isCorruptFile(char* file)
    {
        bool res = false;
        char* des = NULL;
        ZipFileDecompressor* fileHeaders = new ZipFileDecompressor(file,des);
        int numberOfFileHeaders = fileHeaders->headersInfo_.size();

        for (int i = 0; i < numberOfFileHeaders; i++)
        {
            FileHeaderInfo* fileHeader = fileHeaders->headersInfo_.get(i);
            unsigned long calculateCRC = calculateCRC32(fileHeader->fileData_, fileHeader->compressedSize_);
            if (fileHeader->crc_ != calculateCRC)
            {
                res = true;

                INFO("this file is corrupt:%s", fileHeader->fileFullPathName_);
                INFO("expected:%lu got:%lu", fileHeader->crc_, calculateCRC);
                INFO("compressedSize:%d", fileHeader->compressedSize_);
            }
            INFO("this CRC file:%s", fileHeader->fileFullPathName_);
            INFO("expected:%lu got:%lu", fileHeader->crc_, calculateCRC);
         }
        return res;
    }
    
    int lastIndexOf(const char* str, char find)
    {
        int ans = -1;
        int index = 0;
        while (*str != 0)
        {
            if (*str == find)
            {
                ans = index;
            }
            index++;
            str++;
        }
        return ans;
    }
}
